﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using Autofac;
using Wombat.Core;
using IStartable = Wombat.Core.IStartable;

namespace Wombat.ServerHost
{
    public class ServerHostManager: IStartable
    {
        public async Task StartAsync()
        {
            //Load all assemblies in the current directory
            var currentDir = Path.GetDirectoryName(GetType().Assembly.Location) ?? string.Empty;
            var files = Directory.GetFiles(currentDir).Where(f => f.EndsWith(".dll"));
            _container = _container ?? GetContainer(files);
            _bootstrapper = _container.Resolve<IBootstrapper>();
            await _bootstrapper.BootstrapAsync();
        }

        

        private IBootstrapper _bootstrapper;
        private IContainer _container;

        private IContainer GetContainer(IEnumerable<string> files)
        {
            var assemblies = files.Select(System.Reflection.Assembly.LoadFile).ToArray();
            var builder = new ContainerBuilder();
            builder.RegisterAssemblyTypes(assemblies)
                .Where(t => !TypeCatalog.Singletons.ContainsKey(t) && !TypeCatalog.KnownInstances.ContainsKey(t))
                .Except<IGate>()
                .InstancePerDependency();
            foreach (var types in TypeCatalog.Singletons.GroupBy(kvp => kvp.Value))
            {
                var concreteType = types.Key;
                var reg = builder.RegisterType(concreteType);
                foreach (var iface in types)
                {
                    reg.As(iface.Key);
                }
                reg.SingleInstance();
            }
            foreach (var type in TypeCatalog.KnownInstances.Keys)
            {
                builder.RegisterType(TypeCatalog.KnownInstances[type]).As(type).InstancePerDependency();
            }
            foreach (var gate in TypeCatalog.Gates)
            {
                builder.RegisterType(gate).AsSelf().InstancePerDependency();
            }
            builder.Register(c => (IContainer)c).As<IContainer>();
            return builder.Build();
        }

        public async Task StopAsync()
        {
            await Task.Factory.StartNew(() => ((IDisposable)_bootstrapper).Dispose());
        }
    }
}